﻿namespace Holoville.HOTween.Plugins.Core
{
    using FastDynamicMemberAccessor;
    using Holoville.HOTween;
    using Holoville.HOTween.Core;
    using Holoville.HOTween.Core.Easing;
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using UnityEngine;

    public abstract class ABSTweenPlugin
    {
        protected float _duration;
        private bool _easeReversed;
        protected object _endVal;
        private TweenDelegate.HOFunc<Quaternion> _getTransformQuaternion;
        private TweenDelegate.HOFunc<Vector3> _getTransformVector3;
        private bool _initialized;
        protected string _propName;
        private TweenDelegate.HOAction<Quaternion> _setTransformQuaternion;
        private TweenDelegate.HOAction<Vector3> _setTransformVector3;
        protected object _startVal;
        private Transform _transformTarget;
        private bool _useSpeedTransformAccessors;
        [CompilerGenerated]
        private static Dictionary<string, int> <>f__switch$map2;
        protected TweenDelegate.EaseFunc ease;
        private EaseCurve easeCurve;
        private EaseInfo easeInfo;
        private EaseType easeType;
        internal FieldInfo fieldInfo;
        protected bool ignoreAccessor;
        protected bool isRelative;
        private int prevCompletedLoops;
        internal PropertyInfo propInfo;
        private bool speedBasedDurationWasSet;
        internal System.Type targetType;
        protected Tweener tweenObj;
        private IMemberAccessor valAccessor;
        internal bool wasStarted;

        protected ABSTweenPlugin(object p_endVal, bool p_isRelative)
        {
            this.isRelative = p_isRelative;
            this._endVal = p_endVal;
        }

        protected ABSTweenPlugin(object p_endVal, EaseType p_easeType, bool p_isRelative)
        {
            this.isRelative = p_isRelative;
            this._endVal = p_endVal;
            this.easeType = p_easeType;
            this.easeInfo = EaseInfo.GetEaseInfo(p_easeType);
            this.ease = this.easeInfo.ease;
        }

        protected ABSTweenPlugin(object p_endVal, AnimationCurve p_easeAnimCurve, bool p_isRelative)
        {
            this.isRelative = p_isRelative;
            this._endVal = p_endVal;
            this.easeType = EaseType.AnimationCurve;
            this.easeCurve = new EaseCurve(p_easeAnimCurve);
            this.easeInfo = null;
            this.ease = new TweenDelegate.EaseFunc(this.easeCurve.Evaluate);
        }

        internal ABSTweenPlugin CloneBasic()
        {
            object[] args = new object[] { ((this.tweenObj == null) || !this.tweenObj.isFrom) ? this._endVal : this._startVal, this.easeType, this.isRelative };
            return (Activator.CreateInstance(base.GetType(), args) as ABSTweenPlugin);
        }

        internal virtual void Complete()
        {
            this.SetValue(this._endVal);
        }

        protected abstract void DoUpdate(float p_totElapsed);
        internal void ForceSetIncremental(int p_diffIncr)
        {
            this.SetIncremental(p_diffIncr);
        }

        internal void ForceSetSpeedBasedDuration()
        {
            if (!this.speedBasedDurationWasSet)
            {
                this.Startup(true);
            }
        }

        protected abstract float GetSpeedBasedDuration(float p_speed);
        protected virtual object GetValue()
        {
            if (this._useSpeedTransformAccessors)
            {
                if (this._getTransformVector3 != null)
                {
                    return this._getTransformVector3();
                }
                return this._getTransformQuaternion();
            }
            if (!Holoville.HOTween.HOTween.isIOS)
            {
                return this.valAccessor.Get(this.tweenObj.target);
            }
            if (this.propInfo != null)
            {
                return this.propInfo.GetGetMethod().Invoke(this.tweenObj.target, null);
            }
            return this.fieldInfo.GetValue(this.tweenObj.target);
        }

        internal virtual void Init(Tweener p_tweenObj, string p_propertyName, EaseType p_easeType, System.Type p_targetType, PropertyInfo p_propertyInfo, FieldInfo p_fieldInfo)
        {
            this._initialized = true;
            this.tweenObj = p_tweenObj;
            this._propName = p_propertyName;
            this.targetType = p_targetType;
            if (((this.easeType != EaseType.AnimationCurve) && (this.easeInfo == null)) || (this.tweenObj.speedBased || ((this.easeType == EaseType.AnimationCurve) && (this.easeCurve == null))))
            {
                this.SetEase(p_easeType);
            }
            this._duration = this.tweenObj.duration;
            if (this.targetType == typeof(Transform))
            {
                this._transformTarget = p_tweenObj.target as Transform;
                this._useSpeedTransformAccessors = true;
                string key = this._propName;
                if (key != null)
                {
                    int num;
                    if (<>f__switch$map2 == null)
                    {
                        Dictionary<string, int> dictionary = new Dictionary<string, int>(5);
                        dictionary.Add("position", 0);
                        dictionary.Add("localPosition", 1);
                        dictionary.Add("localScale", 2);
                        dictionary.Add("rotation", 3);
                        dictionary.Add("localRotation", 4);
                        <>f__switch$map2 = dictionary;
                    }
                    if (<>f__switch$map2.TryGetValue(key, out num))
                    {
                        switch (num)
                        {
                            case 0:
                                this._setTransformVector3 = (TweenDelegate.HOAction<Vector3>) (value => (this._transformTarget.position = value));
                                this._getTransformVector3 = () => this._transformTarget.position;
                                goto Label_0213;

                            case 1:
                                this._setTransformVector3 = (TweenDelegate.HOAction<Vector3>) (value => (this._transformTarget.localPosition = value));
                                this._getTransformVector3 = () => this._transformTarget.localPosition;
                                goto Label_0213;

                            case 2:
                                this._setTransformVector3 = (TweenDelegate.HOAction<Vector3>) (value => (this._transformTarget.localScale = value));
                                this._getTransformVector3 = () => this._transformTarget.localScale;
                                goto Label_0213;

                            case 3:
                                this._setTransformQuaternion = (TweenDelegate.HOAction<Quaternion>) (value => (this._transformTarget.rotation = value));
                                this._getTransformQuaternion = () => this._transformTarget.rotation;
                                goto Label_0213;

                            case 4:
                                this._setTransformQuaternion = (TweenDelegate.HOAction<Quaternion>) (value => (this._transformTarget.localRotation = value));
                                this._getTransformQuaternion = () => this._transformTarget.localRotation;
                                goto Label_0213;
                        }
                    }
                }
                this._transformTarget = null;
                this._useSpeedTransformAccessors = false;
            }
        Label_0213:
            if (!this._useSpeedTransformAccessors)
            {
                if (Holoville.HOTween.HOTween.isIOS)
                {
                    this.propInfo = p_propertyInfo;
                    this.fieldInfo = p_fieldInfo;
                }
                else if (!this.ignoreAccessor)
                {
                    this.valAccessor = MemberAccessorCacher.Make(p_targetType, p_propertyName, p_propertyInfo, p_fieldInfo);
                }
            }
        }

        internal void ReverseEase()
        {
            this._easeReversed = !this._easeReversed;
            if ((this.easeType != EaseType.AnimationCurve) && (this.easeInfo.inverseEase != null))
            {
                this.ease = !this._easeReversed ? this.easeInfo.ease : this.easeInfo.inverseEase;
            }
        }

        internal virtual void Rewind()
        {
            this.SetValue(this.startVal);
        }

        protected abstract void SetChangeVal();
        internal void SetEase(EaseType p_easeType)
        {
            this.easeType = p_easeType;
            if (this.easeType == EaseType.AnimationCurve)
            {
                if (this.tweenObj._easeAnimationCurve != null)
                {
                    this.easeCurve = new EaseCurve(this.tweenObj._easeAnimationCurve);
                    this.ease = new TweenDelegate.EaseFunc(this.easeCurve.Evaluate);
                }
                else
                {
                    this.easeType = EaseType.EaseOutQuad;
                    this.easeInfo = EaseInfo.GetEaseInfo(this.easeType);
                    this.ease = this.easeInfo.ease;
                }
            }
            else
            {
                this.easeInfo = EaseInfo.GetEaseInfo(this.easeType);
                this.ease = this.easeInfo.ease;
            }
            if (this._easeReversed && (this.easeInfo.inverseEase != null))
            {
                this.ease = this.easeInfo.inverseEase;
            }
        }

        protected abstract void SetIncremental(int p_diffIncr);
        protected virtual void SetValue(object p_value)
        {
            if (this._useSpeedTransformAccessors)
            {
                if (this._setTransformVector3 != null)
                {
                    this._setTransformVector3((Vector3) p_value);
                }
                else
                {
                    this._setTransformQuaternion((Quaternion) p_value);
                }
            }
            else if (Holoville.HOTween.HOTween.isIOS)
            {
                if (this.propInfo != null)
                {
                    try
                    {
                        this.propInfo.SetValue(this.tweenObj.target, p_value, null);
                    }
                    catch (InvalidCastException)
                    {
                        this.propInfo.SetValue(this.tweenObj.target, (int) Math.Floor((double) ((float) p_value)), null);
                    }
                    catch (ArgumentException)
                    {
                        this.propInfo.SetValue(this.tweenObj.target, (int) Math.Floor((double) ((float) p_value)), null);
                    }
                }
                else
                {
                    try
                    {
                        this.fieldInfo.SetValue(this.tweenObj.target, p_value);
                    }
                    catch (InvalidCastException)
                    {
                        this.fieldInfo.SetValue(this.tweenObj.target, (int) Math.Floor((double) ((float) p_value)));
                    }
                    catch (ArgumentException)
                    {
                        this.fieldInfo.SetValue(this.tweenObj.target, (int) Math.Floor((double) ((float) p_value)));
                    }
                }
            }
            else
            {
                try
                {
                    this.valAccessor.Set(this.tweenObj.target, p_value);
                }
                catch (InvalidCastException)
                {
                    this.valAccessor.Set(this.tweenObj.target, (int) Math.Floor((double) ((float) p_value)));
                }
                catch (ArgumentException)
                {
                    this.valAccessor.Set(this.tweenObj.target, (int) Math.Floor((double) ((float) p_value)));
                }
            }
        }

        internal void Startup()
        {
            this.Startup(false);
        }

        internal void Startup(bool p_onlyCalcSpeedBasedDur)
        {
            if (this.wasStarted)
            {
                TweenWarning.Log(string.Concat(new object[] { "Startup() for plugin ", this, " (target: ", this.tweenObj.target, ") has already been called. Startup() won't execute twice." }));
            }
            else
            {
                object obj2 = null;
                object obj3 = null;
                if (p_onlyCalcSpeedBasedDur)
                {
                    if (this.tweenObj.speedBased && !this.speedBasedDurationWasSet)
                    {
                        obj2 = this._startVal;
                        obj3 = this._endVal;
                    }
                }
                else
                {
                    this.wasStarted = true;
                }
                if (this.tweenObj.isFrom)
                {
                    object obj4 = this._endVal;
                    this.endVal = this.GetValue();
                    this.startVal = obj4;
                }
                else
                {
                    this.endVal = this._endVal;
                    this.startVal = this.GetValue();
                }
                this.SetChangeVal();
                if (this.tweenObj.speedBased && !this.speedBasedDurationWasSet)
                {
                    this._duration = this.GetSpeedBasedDuration(this._duration);
                    this.speedBasedDurationWasSet = true;
                    if (p_onlyCalcSpeedBasedDur)
                    {
                        this._startVal = obj2;
                        this._endVal = obj3;
                    }
                }
            }
        }

        internal void Update(float p_totElapsed)
        {
            if (this.tweenObj.loopType == LoopType.Incremental)
            {
                if (this.prevCompletedLoops != this.tweenObj.completedLoops)
                {
                    int completedLoops = this.tweenObj.completedLoops;
                    if ((this.tweenObj._loops != -1) && (completedLoops >= this.tweenObj._loops))
                    {
                        completedLoops--;
                    }
                    int num2 = completedLoops - this.prevCompletedLoops;
                    if (num2 != 0)
                    {
                        this.SetIncremental(num2);
                        this.prevCompletedLoops = completedLoops;
                    }
                }
            }
            else if (this.prevCompletedLoops != 0)
            {
                this.SetIncremental(-this.prevCompletedLoops);
                this.prevCompletedLoops = 0;
            }
            if (p_totElapsed > this._duration)
            {
                p_totElapsed = this._duration;
            }
            this.DoUpdate(p_totElapsed);
        }

        internal virtual bool ValidateTarget(object p_target)
        {
            return true;
        }

        internal float duration
        {
            get
            {
                return this._duration;
            }
        }

        internal bool easeReversed
        {
            get
            {
                return this._easeReversed;
            }
        }

        protected abstract object endVal { get; set; }

        internal bool initialized
        {
            get
            {
                return this._initialized;
            }
        }

        internal virtual int pluginId
        {
            get
            {
                return -1;
            }
        }

        internal string propName
        {
            get
            {
                return this._propName;
            }
        }

        protected abstract object startVal { get; set; }
    }
}

